home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / VideoToolbox / VideoToolboxSources / Assign.note < prev    next >
Encoding:
Text File  |  1993-09-20  |  29.8 KB  |  584 lines  |  [TEXT/KAHL]

  1. Assign.note
  2. This file documents Assign.c.
  3.  
  4. Assign is a portable runtime C interpreter that reads and executes any text
  5. "assignment" file that contains only C assignments and comments, e.g.
  6.     viewingDistance=57.0;    /* inches */
  7. It uses an array of "Description" structures to associate each name in the
  8. assignment file with a corresponding runtime C variable. It can also write an
  9. assignment file, making the assignment file a portable way of writing and
  10. reading calibrations and experimental parameters. Arrays can be allocated
  11. dynamically, automatically dimensioned so as to hold all the assignments in any
  12. part of the assignment file.
  13.  
  14. Programs written before 1993, using the old ReadAssignments.c (now superceded by 
  15. Assign.c), may #include the header file Assign92.h to minimize the effort of 
  16. updating.
  17.  
  18. PORTABILITY: Standard C
  19.  
  20. SYNTAX OF THE ASSIGNMENT FILE
  21.  
  22. The entire "assignment" file may contain only simple assignments--which are
  23. interpreted--and whitespace and comments--which are ignored. Both C style /* */
  24. and C++ style // comments are allowed. Ignoring any intervening whitespace and
  25. comments, each assignment consists of a variable name of any length, possibly
  26. with a constant subscript (of up to ASSIGN_DIMS dimensions), an equal sign,
  27. either a constant (decimal 13, 1.3, 1.3e9, hex 0x1a, char 'a', transcendental
  28. Inf, or not-a-number NaN) or a string literal (e.g. "hello"), and a semicolon.
  29.     i=3; a=1.0; b[1][2]=INF; msg="hello world"; /* examples */
  30. NaN (or NAN or nan), Inf (or INF or inf), and -Inf are accepted as floating
  31. values. (The NAN specification may include a NAN-code, a la THINK C, e.g. NANFF,
  32. or ala MPW C, e.g. NAN[255].) Backslash escapes, e.g. \007 and \n, within single
  33. or double quotes are fully supported (except that there is no support for the
  34. new international "wide" characters and trigraph sequences). A simple variable
  35. name, as in C, consists of an alphabetic character (or _) followed by any number
  36. of alphanumeric characters (or _). To simulate structure references, composite
  37. names are allowed, made up of simple names joined by "." or "->", e.g.
  38.     a->b.c=0.0; myStruct->b=INF;
  39. Unlike C, each line must be less than BUFFER_SIZE characters long (currently
  40. 512). Lines that end with the backslash character \ are spliced to the next by
  41. deleting the backslash and the following newline character. The splice may be
  42. between tokens or inside a comment or string literal, but, unlike C, the splice
  43. may not break a token. Adjacent string literals "a" "b" are concatenated "ab",
  44. as specified by Standard C. (The line splicing and adjacent concatenation allow
  45. creation of strings of arbitrary length, not limited by BUFFER_SIZE.) No further
  46. expression evaluation is supported. No other operators, e.g. +-&*, enums, casts,
  47. e.g. (unsigned long), or number suffixes, e.g. UL, are allowed. No macros or
  48. preprocessor directives are supported (e.g. #if, #define). The syntax rules are
  49. strictly enforced. If ReadAssignmentLine can't interpret your file it will, at
  50. the caller's option, either return an error code or call PrintfExit with an
  51. error message pinpointing the error.
  52.  
  53. Assign.c supports one optional extension beyond C syntax that makes it practical
  54. to save images within assignment files. If a non-string variable is assigned a
  55. string, 
  56.     a="1111aaaa1111";
  57. then ReadAssignmentLine assumes that the string is an encoding of the desired
  58. binary object as a hexadecimal number, and assigns the decoded binary object to
  59. the variable, one byte for every two hex digits. This is supported for both
  60. scalar and array variables--treating either an element or a row (last subscript,
  61. fastest changing) of the array as a single binary object--so you can load or
  62. save a huge row by a single statement that assigns a humungous string of hex
  63. data to the array. E.g. if m[][] is of type char, then the following three lines
  64. are equivalent.
  65.     m[3][0]=155;m[3][1]=95;m[3][2]=255;m[3][3]=127;
  66.     m[3][0]="9b";m[3][1]="5f";m[3][2]="ff";m[3][3]="7f";
  67.     m[3]="9b5fff7f";
  68. This format is supported by both ReadAssignmentLine and PrintAnAssignment. When
  69. reading an assignment file, a binary object containing only one element, as in
  70. m[3][0]="9b", is interpreted as a scalar, rather than as a row of length 1. When
  71. writing an assignment file a whole row of each array is assigned at once
  72. m[3]="9b5fff7f" unless the row is only one element long, in which case each
  73. element is assigned separately. The default behavior of ReadAssignmentLine and
  74. PrintAnAssignment is to use the binary object assignments only for integers
  75. (including char) and to write it only when it would greatly reduce the file
  76. size. The motivation for this extension is to provide a compact way to specify
  77. the contents of an image, typically an array of small integers. It may also be
  78. useful in situations where one wants to save and restore the exact value of a
  79. double, since typical implementations of the C stdio library lose a few bits of
  80. precision translating to or from decimal representations of floating numbers.
  81. You grant or deny permission to read and write hex-encoded binary objects by
  82. setting or clearing two flag bits, assignNoHexInts and assignHexFloats, which
  83. are explained below.
  84.  
  85. DESCRIBING YOUR VARIABLES TO THE ASSIGN ROUTINES
  86.  
  87. The Assign routines use your pre-existing C variables. Each C variable that
  88. you want to be able to load from (or print to) an assignment file must be
  89. described by a "Description" structure, which has fields for the type, name,
  90. address ("ptr"), and other characteristics of your C variable.
  91.     typedef struct {
  92.         short type;
  93.         unsigned sizedOnce:1;    /* Is dim[] meaningful? */
  94.         unsigned sized:1;        /* Is dim[] final? */
  95.         unsigned malloced:1;    /* Allocated by malloc? */
  96.         char *name;
  97.         void *ptr;                /* for array, address of element zero */
  98.         long dim[ASSIGN_DIMS];    /* zero indicates a scalar */
  99.         long firstElement;/* subscript of first element of last dimension. Usually 0 */
  100.         const char *comment;    /* text string, or NULL */
  101.     } Description;
  102. The routines Describe, DescribeArray, and DescribeFirstLast are convenient ways
  103. to set all the fields. Use these routines (instead of explicitly loading the
  104. fields yourself) to enhance the compatibility of your programs with future
  105. enhancements to Assign.c, which might redefine the fields of the Description
  106. structure.
  107.     Description Describe(short type,void *ptr,char *name,const char *comment);
  108.     short n;
  109.     d[i++]=Describe(shortType,&n,"n","hello");
  110. The available types fall into three groups. The basic types correspond to the
  111. basic types in C: charType, unsignedCharType, shortType, unsignedShortType,
  112. longType, unsignedLongType, floatType, shortDoubleType, and doubleType. A
  113. second, corresponding, group of types, adding the word "Ptr", requests dynamic
  114. array allocation: charPtrType, unsignedCharPtrType, shortPtrType,
  115. unsignedShortPtrType, longPtrType, unsignedLongPtrType, floatPtrType,
  116. shortDoublePtrType, and doublePtrType. The third group consists solely of the
  117. "stringType", which is handled somewhat differently from the charPtrType. (Note:
  118. since Standard C doesn't allow the "short double" type, the shortDoubleType and
  119. shortDoublePtrType are conditionally compiled, controlled by SHORT_DOUBLE_OK,
  120. which is defined in VideoToolbox.h.) The name argument string is used in reading the
  121. assignment file. The ptr argument should be the address of a C variable of the
  122. type specified by the type argument (e.g. float). When the type is one of the
  123. Ptr types, or stringType, then the C variable should be a pointer of the
  124. appropriate kind, so the "ptr" argument you supply will be the address of that
  125. pointer. The last argument to Describe() is comment, which must be a string or
  126. NULL. Any call to PrintAnAssignment() will print the comment (if not NULL) after
  127. the assignment statement, surrounding it by /* */.
  128.     Description DescribeArray(short type,void *ptr,char *name,const char *comment,...);
  129.     double b[3][4];
  130.     d[i++]=DescribeArray(doubleType,&b,"b","coefficients",3L,4L,0L);
  131. For the basic and string types, the supplied C variable can be an array, whose
  132. dimensions are specified as additional arguments to DescribeArray. There may
  133. be up to ASSIGN_DIMS dimensions. Each dimension must be a long, and the argument
  134. list must be terminated by 0L, i.e. a zero of type long.
  135.  
  136. Arrays of stringType are allowed, e.g. 
  137.     char *nicknames[10];
  138.     DescribeArray(stringType,&nicknames,"nicknames",NULL,10L,0L);
  139. But, in that case, malloced space for a string is not freed when a new string 
  140. is assigned.
  141.  
  142. READING AN ASSIGNMENT FILE
  143.  
  144. ReadAssignmentLine does all the reading. ReadAssignmentBlock and
  145. ReadAssignmentFile just call ReadAssignmentLine repeatedly. One by one,
  146. ReadAssignmentLine reads assignments from the assignment file (until it reaches
  147. the end of the line, or detects an error). Syntax errors are reported.
  148. ReadAssignmentLine gets a variable name from the assignment file and looks for a
  149. matching name in the user-supplied Description array. Any inconsistency of the
  150. assignment statement with the variable's declared type and dimensions is
  151. reported. Then the assignment is made.
  152.  
  153. Assignment to basic variables is straightforward, equivalent to assignment in
  154. a C program, e.g.
  155.     a[2][1]=3.0;
  156. When ReadAssignmentLine assigns a string to a stringType variable,
  157.     s="hello world";
  158. the string is allocated by malloc() and the string's address is poked into your
  159. char * variable. Prior to assignment of a string, FreeADescribedVar will be
  160. called, which, if any pre-existing string was allocated by malloc--as indicated
  161. by the d->malloced flag--will free it. You can free all your strings (and
  162. PtrType variables) by calling FreeDescribedVars.
  163.  
  164. The PtrType variables initially have no space allocation for storage of data. Each
  165. unallocated Ptr variable is automatically allocated space for a scalar or array
  166. dimensioned just big enough to contain all the assignments in the part (or
  167. "gulp") of the assignment file that the user has just asked to read: a line, a
  168. block, or the whole file. (If the Ptr variable is dimensioned, from a call to
  169. DescribeArray, but not allocated, then it will be allocated at the declared
  170. size.) Once allocated, the array dimensions are fixed, unless the user frees the
  171. allocations by calling FreeDescribedPtrVars() or FreeDescribedVars(), which also
  172. clear the array's dimensions (whether set dynamically or by an initial call to
  173. DescribeArray). Restricting the scan to the current gulp makes it possible to
  174. read assignment files in which the array sizes change from gulp to gulp,
  175. provided only that between gulps the user calls FreeDescribedPtrVars() or
  176. FreeDescribedVars(). An inconsistent number of array dimensions
  177.     a[0]=1; a[0][0]=1;
  178. within a gulp is flagged as an error. 
  179.  
  180. ROUTINES
  181.  
  182.     stream=OpenCalFileWrite(filename);
  183. Open up a calibration file for appending. If the file exists in the current
  184. directory, it is used. If not, then if it exists in the Preferences folder, it
  185. used. If not, the file is created in the Preferences folder.
  186.  
  187.     stream=OpenCalFileRead(filename);
  188. Open up a calibration file for reading. First looks in the current directory,
  189. then in the preferences folder. On success returns the opened file's stream. On
  190. failure returns NULL.
  191.  
  192.     stream=OpenCalFileReadAndCheck(filename);
  193. Open up a calibration file for reading. If the file exists in the current
  194. directory, it is used. If not, then if it exists in the preferences folder, it
  195. used. If no file is found then prints an error message and exits.
  196.  
  197.     AppendDescriptions(&d,s);
  198. Appends the second descriptions array onto the end of the first, which is
  199. reallocated with more space. The source array is not freed; the caller should do
  200. that. Both arrays must be null-terminated.
  201.  
  202.     CopyDescriptions(d,s);
  203. Copy one null-terminated array of descriptions to another, which is assumed to
  204. be big enough.
  205.  
  206.     d=AllocateDescriptions(n);
  207. Allocate space for variable descriptions. Adds one to the passed size to hold
  208. the null descriptor. Nulls the first element.
  209.  
  210.     FreeDescriptions(d);
  211. Free the descriptions array. Doesn't affect the described variables.
  212.  
  213.     n=NumberOfDescriptions(d);
  214. Find the size of an array of descriptions. Does not count the trailing null
  215. description.
  216.  
  217.     d[i]=NullDescription();
  218. Returns a null description, to terminate a descriptions array.
  219.  
  220.     if( IsNullDescription(d[i]) )...;
  221. Determine whether we are looking at a null description. Implemented as a macro.
  222.  
  223. Description Describe(short type,void *ptr,char *name,const char *comment);
  224. Description DescribeArray(short type,void *ptr,char *name,const char *comment,...);
  225.     double a,*p,x[3];
  226.     d[i++]=Describe(doubleType,&a,"a","hello");
  227.     d[i++]=Describe(doublePtrType,&p,"p",NULL);
  228.     d[i++]=DescribeArray(doubleType,&x,"x",NULL,3L,0L);
  229. Describe and DescribeArray merely return a Description with the field values
  230. that you supply. Use them to make your programs more readable, and to enhance
  231. the compatibility of your programs with future enhancements to Assign.c, which
  232. might redefine the fields of the Description structure. DescribeArray() accepts
  233. a variable number of arguments specifying the array dimensions. You may supply
  234. any number of array dimensions (up to ASSIGN_DIMS), but they MUST be long, and
  235. the argument list MUST be terminated by a 0L following the list of dimensions.
  236. Any additional arguments following the 0L are ignored. A PtrType variable may be
  237. described by DescribeArray(), specifying the dimensions of the storage area to
  238. be allocated, or may be described by Describe() in which case the dimensions
  239. (none up to ASSIGN_DIMS) will be determined from the first gulp of the
  240. assignment file. In either case, storage for the PtrType variable is allocated
  241. only when it is encountered in the assignment file. The array dimensions of a
  242. PtrType variable specified when calling DescribeArray() are wiped out if you
  243. later call FreePtrVariables(), with the same result as just calling Describe().
  244.  
  245. TYPES: charType, unsignedCharType, shortType, unsignedShortType, longType,
  246. unsignedLongType, floatType, shortDoubleType, doubleType, charPtrType,
  247. unsignedCharPtrType, shortPtrType, unsignedShortPtrType, longPtrType,
  248. unsignedLongPtrType, floatPtrType, shortDoublePtrType, doublePtrType,
  249. stringType.
  250.  
  251. Description DescribeFirstLast(short type,void *ptr,char *name
  252.     ,const char *comment,long firstElement,long lastElement);
  253.     float *a;
  254.     a=vector(1,10);    /* a Numerical Recipes in C allocation routine */
  255.     d[i++]=DescribeFirstLast(floatType,a,"a",NULL,1L,10L,0L);
  256. This allows you to specify a 1-dimensional array with a nonstandard subscript
  257. range, e.g. starting with subscript 1, as in Numerical Recipes in C. The "ptr"
  258. argument should always point to element zero, even if that element is not part of
  259. the array's allocated storage. 
  260.  
  261.     error=UnequalDescribedVars(descriptions1,descriptions2,flags);
  262.     error=UnequalDescribedVarPair(d1,d2,flags);
  263. These routines compare the data pointed to by the two Description arrays or
  264. structs. They return 0 if the Descriptions are legal and the data are
  265. equal, and a nonzero error code (or PrintfExit, depending on flags) otherwise.
  266. (Comparison of floating numbers allows a tolerance of +/- one part in a million,
  267. because converting to and from decimal may lose some precision, and considers
  268. all NANs equal because NAN indices (NAN04 vs NANFF) are not preserved by most
  269. operations.) This makes it easy to verify what was written to an assignment
  270. file. Just create a new data structure and a Description array describing it,
  271. call ReadAssignmentFile, and use UnequalDescribedVars to verify that you read
  272. back exactly what you wrote.
  273.  
  274.     n=InitializeDescribedVars(descriptions,flags);
  275.     n=InitializeADescribedVar(d,flags);
  276. Initialize the described variables. All integer variables
  277. are set to zero, all floating variables are set to NAN, and all the strings are
  278. set to point to a particular empty string "". Any PtrType scalars and arrays
  279. that have already been allocated will be initialized; unallocated PtrType
  280. variables are NULLed.
  281.  
  282.     n=ReadAssignmentLine(stream,descriptions,flags);
  283. Interprets one line from the stream (splicing continuation lines), and continues
  284. to read further lines, if necessary, to reach the end of any incomplete comment
  285. or assignment. ReadAssignmentBlock() and ReadAssignmentFile(), below, do all
  286. their reading by repeatedly calling ReadAssignmentLine().
  287.  
  288.     blank=AssignmentLineWasBlank();
  289. Returns true (i.e. 1) unless the most recent call to ReadAssignmentLine() read
  290. some non-blank text, in which case it returns false (i.e. 0).
  291.  
  292.     n=ReadAssignmentBlock(stream,descriptions,flags);
  293. Interprets lines from the stream until it reads a blank line. (Blank lines within
  294. an assignment or comment /* */ are ignored.) Implemented by repeatedly calling
  295. ReadAssignmentLine() until AssignmentLineWasBlank() is true. 
  296.  
  297.     n=ReadAssignmentFile(filename,descriptions,flags);
  298. Interpret a whole file. Implemented by repeatedly calling ReadAssignmentLine().
  299.  
  300.     FreeDescribedPtrVars(descriptions,flags);
  301. Frees any allocated storage (and wipes out the array dimensions) for any
  302. described PtrType variables; they will be appropriately dimensioned and
  303. allocated when they are next read from an assignment file. This allows reading
  304. of assignment files in which array dimensions may change from gulp to gulp.
  305.  
  306.     FreeDescribedVars(descriptions,flags);
  307. Frees any allocated storage (and wipes out the array dimensions) for any
  308. described PtrType and stringType variables.
  309.  
  310.     FreeADescribedVar(description,flags);
  311. Frees any allocated storage (and wipes out the array dimensions) for a described
  312. variable. This only affects PtrType and stringType variables.
  313.  
  314.     KeepDescribedVars(descriptions,flags);
  315. Prevents the freeing of all the allocated storage for all the described PtrType
  316. and stringType variables. Call this when you want to copy the pointer elsewhere
  317. and you don't want Assign to dispose of the storage pointed to. (This routine
  318. simply clears all the "malloced" fields in the descriptions.)
  319.  
  320.     i=FindDescription(d,ptr,flags);
  321. Finds your C variable's description in the supplied array. Returns the subscript
  322. (≥0) of the matching Description, or, if the search fails, then either PrintfExits
  323. with an error or returns a negative error code, as determined by the setting of
  324. the assignNoPrintfExit bit in flags. Your C variable's dimensions are in the
  325. d[i].dim[] field, which is dimensioned ASSIGN_DIMS.
  326.  
  327.     dim=FindDescribedDim(d,ptr,n,flags);
  328. Calls FindDescription to find your C variable's description and returns the
  329. size of your variable's n-th dimension. (All dimensions after the first
  330. ASSIGN_DIMS return zero.) Handling of search failure as in FindDescription().
  331.  
  332.     n=PrintAnAssignment(stream,d,flags);
  333. Prints out the name and value of the described variable as an assignment
  334. statement "i=2;" suitable for reading by ReadAssignmentLine.
  335.  
  336.     n=PrintAssignments(stream,descriptions,flags);
  337. Calls PrintAnAssignment and fprintf(stream,"\n"); for each described variable.
  338.  
  339.     n=PrintAssignmentsToFile(filename,descriptions,flags);
  340. Opens the file, calls PrintAssignments, and closes the file. If a file of that 
  341. name already exists it appends to the existing file.
  342.  
  343.     n=ReadLuminanceRecord(filename,LP,flags)
  344. This uses ReadAssignmentFile() to interpret a LuminanceRecord?.h file. This
  345. routine is in ReadLuminanceRecord.c.
  346.  
  347. In all cases the returned value, n, is either positive (>=0) indicating the
  348. number of data that were fully processed, or negative, indicating an error code
  349. defined in VideoToolbox.h. Each array element, scalar, or string is considered a
  350. datum. Any assignments that referred to out-of-range array elements or unknown
  351. variables are skipped and are not counted.
  352.  
  353. The first argument is either a filename (c string) or a stream (FILE *)
  354. returned by fopen(). Open the file in text, not binary, mode, so that
  355. '\r' characters will be translated properly.
  356.  
  357. The second argument, "descriptions", is an array of Descriptions of
  358. your variables. The number of array elements is not given. Instead you mark the
  359. end by zeroing the "type" field of the last Description. The "Description" data
  360. structure is defined in VideoToolbox.h.
  361.  
  362. The third argument, "flags", allows you to specify various runtime options. Each
  363. option is controlled by a different bit; flags is the sum of the desired
  364. options. Most users will want the default behavior, i.e. flags==0. The default
  365. behavior of PrintAnAssignment is to never hex-encode floats (float and double)
  366. and to only hex encode integers (i.e. char, short, and long, signed or unsigned)
  367. when this would reduce the number of lines in the assignment file (i.e. when
  368. the last dimension exceeds typeSize+2).
  369.  
  370. FLAGS
  371.  
  372. "assignNoPrintfExit" is a flag that asks all the routines to return an error
  373. code if they cannot satisfy the request, otherwise the routines call PrintfExit
  374. with a diagnostic error message that pinpoints the location of the error.
  375.  
  376. "assignReportUnknown" asks ReadAssignmentLine to report an error if an unknown
  377. variable appears in the assignment file. Array elements with out-of-range
  378. subscripts are considered unknown variables. In the absence of this flag,
  379. attempts to assign to unknown variables are silently skipped (the data are
  380. discarded).
  381.  
  382. "assignNoHexInts" tells ReadAssignmentLine and PrintAnAssignment to never read
  383. or save char, short, or long as hex strings. This sacrifices the compactness of
  384. hex strings, but enhances human readability of the assignment file. (It also
  385. preserves compatibility with C, making it possible to #include the assignment
  386. file inside a C program, and preserves portability of the assignment file
  387. between computers that use different byte orderings.)
  388.  
  389. "assignHexFloats" tells PrintAnAssignment to always save floats (float and
  390. double) as hex strings, and tells ReadAssignmentLine to allow hex strings. This
  391. preserves the exact value (unlike decimal representation, which loses a few
  392. least-significant bits in typical implementations of the C stdio library), but
  393. sacrifices human readability and portability of the assignment file since the
  394. binary representation of floats is highly dependent on the compiler options and
  395. the kind of computer. (It also sacrifices compatibility with C, making it
  396. impossible to #include the assignment file.)
  397.  
  398. "assignNoComment" tells PrintAnAssignment not to print the comment field.
  399.  
  400. "assignEchoFile", primarily an aid to debugging, prints each line from the stream
  401. as it is read by ReadAssignmentLine.
  402.  
  403. "assignEchoAssignments", primarily an aid to debugging, calls PrintAnAssignment
  404. after each assignment is performed by ReadAssignmentLine. Uncommented newline
  405. characters in the assignment file are echoed as well. (If assignReportUnknown is
  406. off then assignment statements containing unknown variables or out-of-bounds
  407. array references are echoed as comments: /*UNKNOWN: x=3; */.)
  408.  
  409. "assignEchoComments", primarily an aid to debugging, prints both /*..*/ and
  410. //-style comments as they are read by ReadAssignmentLine. Uncommented newline
  411. characters in the assignment file are echoed as well.
  412.  
  413. ERRORS
  414.  
  415. An error code is returned only if the assignNoPrintfExit flag is set. Otherwise
  416. PrintfExit() is called with a diagnostic message.
  417.  
  418. -1 assignMemoryError: couldn't allocate enough memory.
  419. -2 assignTypeError: unknown type, or array of string, which is not allowed.
  420. -3 assignVariableError: couldn't parse the variable name.
  421. -4 assignUnknownVariableError: unknown variable; can only occur if the 
  422.     assignReportUnknown flag is set.
  423. -5 assignSubscriptError: couldn't parse the subscript.
  424. -6 assignSubscriptBoundsError: out-of-bounds array element; this error is flagged only 
  425.     if the assignReportUnknown flag is set.
  426. -7 assignEqualsError: couldn't find the equals sign.
  427. -8 assignConstantError: couldn't parse the constant.
  428. -9 assignHexError: couldn't parse a hex-encoded binary object constant.
  429. -10 assignSemicolonError: couldn't find the semicolon.
  430. -11 assignFileError: couldn't open the file.
  431. -12 assignInconsistentDescriptionsError: two descriptions are inconsistent.
  432. -13 assignUnequalDataError: two described variables have significantly different data.
  433.  
  434. IMPORTANT: Do not forget to mark the end of your Description array by a Description 
  435. with a type of zero.
  436.  
  437. USING ASSIGN.C
  438.  
  439. It is suggested that those who want to use this package create a header file
  440. with a typedef for a data structure, and write a subroutine that allocates and
  441. fills a Description array describing the data structure's fields. For example,
  442. Luminance.h defines the luminanceRecord structure and ReadLuminanceRecord.c 
  443. contains the function,
  444.     Description *DescribeLuminanceRecord(luminanceRecord *LP);
  445. that creates a Description array describing the particular luminanceRecord structure.
  446.  
  447. CONTROLLING EXPERIMENTS
  448.  
  449. Assign.c was originally written to read parameter files that control
  450. experiments. Typical psychophysical and physiological experiments are very
  451. complicated and require lots of adjustable parameters. One needs an easy way to
  452. change them all that is self documenting and easily reproduced, possibly months
  453. later. The routines provided here come in various flavors allowing you to read a
  454. line at a time (with any number of assignments on the line), a block at a time
  455. (blocks are separated by blank lines), or a whole file at a time. A line may be
  456. continued by ending it with backslash \. In controlling psychophysical
  457. experiments I use a block at the beginning of the file to define the general
  458. experiment followed by a block for each psychophysical "block"; within the block
  459. each line specifies a different experimental condition.
  460.  
  461. If you decide to read the assignment file a bit at a time, bear in mind that
  462. ReadAssignmentLine will immediately return or PrintfExit if the assignment file
  463. contains even a single error. It is strongly suggested that your experimental
  464. program begin by doing a dry run, reading the whole assignment file through to
  465. check for errors, before initializing your variables, and reading it again a bit
  466. at a time as the experiment progresses. It would obviously be very bad to have
  467. the interpreter quit near the end of a 3 hour experiment.
  468.  
  469. READING AND WRITING CALIBRATION DATA
  470.  
  471. David Brainard and I have been discussing how to save and read calibrations of
  472. video displays in a portable way, so that the vision community could share
  473. calibration programs, and experimental programs could simply read in the data
  474. associated with the particular display. The current idea is that there would be
  475. a text file called "Monitor nn calib" associated with each display (where nn is
  476. the video card's slot number), and that this file would hold all kinds of
  477. calibration data for this display, typically produced by a variety of
  478. calibration programs that would each append their results. On a Macintosh
  479. computer these calibration files would reside in the Preferences folder. (Where
  480. should they go on a DOS machine?) David has developed color calibration software
  481. and I've developed software to calibrate gamma and MTF. We are now rewriting
  482. these to make them more portable. We have begun drafting an open-ended standard
  483. for this calibration file, to allow any number of programs to read and write to
  484. it, extracting or adding the data they need and know about and ignoring the
  485. rest. Tentatively, in order to conform to this calibration standard a new
  486. supplement (e.g. to calibrate the geometry of the display) should include: 1. a
  487. C header file that defines a suitable data structure to hold the measurements
  488. (and a few standard facts, e.g. the date of calibration, the name of the video
  489. card and serial number of the monitor, and the names of the person and program
  490. that did the calibration), 2. a C subroutine that accepts a pointer to such a
  491. data structure and returns a pointer to a "Description" array describing each of
  492. the data structure's fields. 3. a program (in any language) that makes the
  493. measurements and appends them to the monitor's calibration file as C assignments
  494. to the data structure's fields, which is easily accomplished by one call to
  495. PrintAssignmentFile. These C assignments must be readable by ReadAssignmentFile
  496. using the Description array created in 2. above, and it is strongly recommended
  497. that the calibration program itself call ReadAssignmentFile, and use
  498. UnequalDescribedVars() to verify that it read back exactly what it wrote. 4.
  499. finally, it will normally be important to provide some sort of advice on how to
  500. use the calibration data when they are read from the calibration file.
  501.  
  502. EXAMPLE
  503.  
  504. An assignment file might contain this:
  505.     /* first block */
  506.     viewingDistance=57.0;
  507.     trials=40;
  508.     message="Monitor calibrated November 21, 1993 by Katie Burns";
  509.     a=3;
  510.     
  511.     // second block
  512.     logC=-1.0;
  513.     a[0]=1;
  514.     
  515.     // third block
  516.     logC=-2; 
  517.     a[1][1]=1.1;a[0][0]=-INF;
  518.  
  519. Here is a sample program to read the assignments given above:
  520. #include "VideoToolbox.h"
  521. #include "assert.h"
  522. typedef struct {
  523.     double *a,logC,viewingDistance;
  524.     long trials;
  525.     char *message;
  526. } Psychophysics;
  527. Description *DescribePsychophysics(Psychophysics *p);
  528.  
  529. Description *DescribePsychophysics(Psychophysics *p)
  530. {
  531.     Description *d;
  532.     int i;
  533.     
  534.     d=AllocateDescriptions(10);
  535.     i=0;
  536.     d[i++]=Describe(stringType,&p->message,"message",NULL);
  537.     d[i++]=Describe(doubleType,&p->viewingDistance,"viewingDistance",NULL);
  538.     d[i++]=Describe(shortType,&p->trials,"trials",NULL);
  539.     d[i++]=Describe(doubleType,&p->logC,"logC",NULL);
  540.     d[i++]=Describe(doublePtrType,&p->a,"a",NULL);
  541.     assert(i<=10);        /*  make sure array was big enough */
  542.     d[i++]=NullDescription();        /*  mark end of array */
  543.     return d;
  544. }
  545.  
  546. void main(void)
  547. {
  548.     Description *d;
  549.     Psychophysics psychophysics,*p;
  550.     short i,flags=0;
  551.     FILE *stream;
  552.     
  553.     p=&psychophysics;
  554.     d=DescribePsychophysics(p);
  555.     InitializeDescribedVars(d,flags);
  556.     stream=fopen("assignments","r");
  557.     do{
  558.         printf("\n/******** New block ********/\n");
  559.         ReadAssignmentBlock(stream,d,flags);
  560.         /*
  561.         a real program would do something useful here with the data in p
  562.         */
  563.         PrintAssignments(stdout,d,flags);
  564.         FreeDescribedPtrVars(d,flags);
  565.     } while(!feof(stream));
  566.     fclose(stream);
  567.     FreeDescriptions(d);
  568. }
  569.  
  570. NOTES FOR FUTURE ENHANCEMENT
  571. The "firstElement" approach supports Numerical Recipes vectors, i.e. 1-d arrays.
  572. For multi-dimensional Numerical Recipes arrays I would also need a
  573. "vectoredArray" flag. Vectored arrays would be fairly easy to add, only
  574. affecting ElementPtr, and allocation and freeing. In the meantime, note that
  575. Numerical Recipes provides a convert_matrix routine that provides vectored
  576. addressing of a normal 2-d c array.
  577.  
  578. ACKNOWLEDGEMENTS
  579. Assign.c was inspired by an idea Beau Watson mentioned to me in the 1980's: a
  580. routine to read free-form parameter values at run time. Discussions with David
  581. Brainard motivated the extensions to support arrays, dynamic allocation, and
  582. unknown variables.
  583.  
  584.